package org.starsource.forum.server.dao.test;

import static org.junit.Assert.*;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Date;
import java.util.Set;
import java.sql.Timestamp;

import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import org.starsource.forum.client.exception.DataNotFoundException;
import org.starsource.forum.client.exception.DatabaseException;
import org.starsource.forum.server.dao.CategoryDao;
import org.starsource.forum.server.dao.MessageDao;
import org.starsource.forum.server.dao.SessionDao;
import org.starsource.forum.server.dao.UserDao;
import org.starsource.forum.server.domain.Category;
import org.starsource.forum.server.domain.Message;
import org.starsource.forum.server.domain.Session;
import org.starsource.forum.server.domain.User;

public abstract class AbsTestMessageDao {

	@Autowired
	private UserDao userDao;
	
	@Autowired
	private SessionDao sessionDao;
	
	@Autowired
	private MessageDao messageDao;
	
	@Autowired
	private CategoryDao categoryDao;

	@Test
	public void testSave() throws DatabaseException {
		User user1 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user1);

		Category category1 = new Category(null, "NAME_FOR_UNIT_TEST", "CAPTION_FOR_UNIT_TEST");
		categoryDao.save(category1);
		
		Timestamp createTimestamp, updateTimestamp;
		createTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		try {
			Thread.sleep(1000);			
		} catch (InterruptedException e) {
			fail("Test fail because thread sleep");
		}
		updateTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		Session session1 = new Session(user1, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session1);
		
		int round = 10;
		Set<Message> messageSet1 = new LinkedHashSet<Message>();
		for(int j = 0; j<round; j++) {
			Message message1 = new Message(1, user1, "CONTENT_FOR_TEST", session1, createTimestamp, updateTimestamp);
			messageDao.save(message1);
			messageSet1.add(message1);			
		}

		Session session2 = sessionDao.getSession(session1.getId());
		
		Iterator<Message> iterator1 = messageSet1.iterator();
		while (iterator1.hasNext()) {
			Message message = iterator1.next();
			Iterator<Message> iterator2 = session2.getMessages().iterator();
			boolean found = false;
			while (iterator2.hasNext()) {
				if (iterator2.next().equals(message)) {
					found = true;
				}
			}
			assertTrue(found);
		}

	}

	@Test
	public void testUpdate() throws DatabaseException {
		User user1 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user1);
		
		User user2 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user2);

		Category category1 = new Category(null, "NAME_FOR_UNIT_TEST", "CAPTION_FOR_UNIT_TEST");
		categoryDao.save(category1);

		Timestamp createTimestamp, updateTimestamp;
		createTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		try {
			Thread.sleep(1000);			
		} catch (InterruptedException e) {
			fail("Test fail because thread sleep");
		}
		updateTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		Session session1 = new Session(user1, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session1);
		
		Session session2 = new Session(user2, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session2);

		Message message1 = new Message(1, user1, "CONTENT_FOR_TEST", session1, createTimestamp, updateTimestamp);
		messageDao.save(message1);
		
		session1.getMessages().remove(message1);
		session2.getMessages().add(message1);
		message1.setOwner(user2);
		message1.setContent("NEW_CONTENT_FOR_TEST");
		message1.setSession(session2);
		messageDao.update(message1);

		Session session3 = sessionDao.getSession(session2.getId());
		
		Iterator<Message> iterator = session3.getMessages().iterator();
		boolean found = false;
		while (iterator.hasNext()) {
			if (iterator.next().equals(message1)) {
				found = true;
			}
		}
		assertTrue(found);

	}

	@Test
	public void testDelete() throws DatabaseException {
		User user1 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user1);
		
		Category category1 = new Category(null, "NAME_FOR_UNIT_TEST", "CAPTION_FOR_UNIT_TEST");
		categoryDao.save(category1);

		Timestamp createTimestamp, updateTimestamp;
		createTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		try {
			Thread.sleep(1000);			
		} catch (InterruptedException e) {
			fail("Test fail because thread sleep");
		}
		updateTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		Session session1 = new Session(user1, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session1);
		
		Message message1 = new Message(1, user1, "CONTENT_FOR_TEST", session1, createTimestamp, updateTimestamp);
		messageDao.save(message1);
		
		int messageId = message1.getId();
		messageDao.delete(message1);
		try {
			messageDao.getMessage(messageId);
			assertTrue(false);
		} catch (DataNotFoundException e) {
		}
	}

	@Test
	public void testGetMessage() throws DatabaseException {
		User user1 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user1);

		Category category1 = new Category(null, "NAME_FOR_UNIT_TEST", "CAPTION_FOR_UNIT_TEST");
		categoryDao.save(category1);
		
		Timestamp createTimestamp, updateTimestamp;
		createTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		try {
			Thread.sleep(1000);			
		} catch (InterruptedException e) {
			fail("Test fail because thread sleep");
		}
		updateTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		Session session1 = new Session(user1, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session1);
		
		Message message1 = new Message(1, user1, "CONTENT_FOR_TEST", session1, createTimestamp, updateTimestamp);
		messageDao.save(message1);

		Message message2 = messageDao.getMessage(message1.getId());
		
		assertEquals(message1, message2);
	}

	@Test
	public void testGetMessageSet() throws DatabaseException {
		User user1 = new User("ONLY_FOR_UNIT_TEST", "PASSWORD_FOR_TEST", "NAME_FOR_TEST", "DIRECTORY_FOR_TEST");
		userDao.save(user1);

		Category category1 = new Category(null, "NAME_FOR_UNIT_TEST", "CAPTION_FOR_UNIT_TEST");
		categoryDao.save(category1);
		
		Timestamp createTimestamp, updateTimestamp;
		createTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		try {
			Thread.sleep(1000);			
		} catch (InterruptedException e) {
			fail("Test fail because thread sleep");
		}
		updateTimestamp = new Timestamp(new Date().getTime()/1000*1000); 
		Session session1 = new Session(user1, "TITLE_FOR_TEST", category1, createTimestamp, updateTimestamp);
		sessionDao.save(session1);
		
		Set<Message> messageSet1 = new LinkedHashSet<Message>();
		for(int index = 0; index < 10; index ++) {
			Message message1 = new Message(1, user1, "CONTENT_FOR_TEST", session1, createTimestamp, updateTimestamp);
			messageDao.save(message1);
			messageSet1.add(message1);
		}
		
		Set<Message> messageSet2 = messageDao.getMessageSet(session1);
		assertTrue(messageSet2.size() >= 10);
		
		Iterator<Message> iterator1 = messageSet1.iterator();
		while (iterator1.hasNext()) {
			Message message = iterator1.next();
			Iterator<Message> iterator2 = messageSet2.iterator();
			boolean found = false;
			while (iterator2.hasNext()) {
				if (iterator2.next().equals(message)) {
					found = true;
				}
			}
			assertTrue(found);
		}

	}
}
